#pragma	once

#include <vector>
#include <string>
#include <math.h>
#include "TMatrix.h"
#include "LeafNode.h"
#include "Parameter.h"

using	namespace	std;

class	CAndNodeModel;
class	COrNodeModel;
class	CLeafNodeModel;
class	CAndNode;
class	COrNode;
class	CLeafNode;

class BasicNodeType
{
public:
	double	x, y;
	double	ori;

public:
	bool InputFromStream(istream& inStream) { return !!(inStream>>x>>y>>ori); }
	void OutputToStream(ostream& outStream) const { outStream<<setprecision(6)<<"\t"<<fixed<<x<<"\t"<<fixed<<y<<"\t"<<fixed<<ori; }
};

class BasicNodePairType
{
public:
	BasicNodeType	node;
	int				LeafNodeIndex;
	int				Missing;
	int				FixCount;

public:
	bool InputFromStream(istream& inStream)
	{
		if (!node.InputFromStream(inStream)) return false;
		return !!(inStream>>LeafNodeIndex>>Missing>>FixCount);
	}
	void OutputToStream(ostream& outStream) const
	{
		node.OutputToStream(outStream);
		outStream<<"\t\t"<<LeafNodeIndex<<"\t"<<Missing<<"\t"<<FixCount;
	}
};

class BasicInstInfoType
{
public:
	double		x, y;
	double		ori, scale;
	int			OrIndex;				// for proposals in OR nodes

public:
	BasicInstInfoType()
	{
		x = y = 0.0;
		ori = 0.0;
		scale = 1.0;
		OrIndex = -1;
	}
	bool InputFromStream(istream& inStream) { return !!(inStream>>x>>y>>ori>>scale>>OrIndex); }
	void OutputToStream(ostream& outStream) const
	{
		outStream<<setprecision(6)
			<<"\t"<<fixed<<x
			<<"\t"<<fixed<<y
			<<"\t"<<fixed<<ori
			<<"\t"<<fixed<<scale
			<<"\t"<<OrIndex
			;
	}
};

class NodeInstanceType
{
public:
	vector<BasicNodePairType>		LeafNodeInfo;
	vector<BasicInstInfoType>		ChildCenters;
	vector<BasicInstInfoType>		Centers;
	vector<int>						source;
	BasicInstInfoType				center;
	double							Score, ShapeScore, AppearanceScore, NodeBaseAppearanceScore;

public:
	NodeInstanceType()
	{
		LeafNodeInfo.clear();
		ChildCenters.clear();
		Centers.clear();
		source.clear();
		center = BasicInstInfoType();
		Score = ShapeScore = AppearanceScore = NodeBaseAppearanceScore = 0.0;
	}
	bool InputFromStream(istream& inStream)
	{
		if (!(center.InputFromStream(inStream))) return false;
		if (!(inStream
			>>Score
			>>ShapeScore
			>>AppearanceScore
			>>NodeBaseAppearanceScore
			))
			return false;
		int i, tn;
		if (!(inStream>>tn)) return false;
		LeafNodeInfo.resize(tn); for ( i = 0; i < tn; ++i ) if (!(LeafNodeInfo[i].InputFromStream(inStream))) return false;
		if (!(inStream>>tn)) return false;
		ChildCenters.resize(tn); for ( i = 0; i < tn; ++i ) if (!(ChildCenters[i].InputFromStream(inStream))) return false;
		if (!(inStream>>tn)) return false;
		Centers.resize(tn); for ( i = 0; i < tn; ++i ) if (!(Centers[i].InputFromStream(inStream))) return false;
		if (!(inStream>>tn)) return false;
		source.resize(tn); for ( i = 0; i < tn; ++i ) if (!(inStream>>source[i])) return false;
		return true;
	}
	void OutputToStream(ostream& outStream) const
	{
		center.OutputToStream(outStream); outStream<<endl;
		outStream<<setprecision(6)
			<<"\t"<<fixed<<Score
			<<"\t"<<fixed<<ShapeScore
			<<"\t"<<fixed<<AppearanceScore
			<<"\t"<<fixed<<NodeBaseAppearanceScore
			<<endl;
		int i, tn;
		outStream<<(tn = (int)LeafNodeInfo.size())<<endl;
		for ( i = 0; i < tn; ++i ) { LeafNodeInfo[i].OutputToStream(outStream); outStream<<endl; }
		outStream<<(tn = (int)ChildCenters.size())<<endl;
		for ( i = 0; i < tn; ++i ) { ChildCenters[i].OutputToStream(outStream); outStream<<endl; }
		outStream<<(tn = (int)Centers.size())<<endl;
		for ( i = 0; i < tn; ++i ) { Centers[i].OutputToStream(outStream); outStream<<endl; }
		outStream<<(tn = (int)source.size())<<endl;
		for ( i = 0; i < tn; ++i ) outStream<<"\t"<<source[i];
		outStream<<endl;
	}
};

class InstanceTreeType
{
public:
	vector<CAndNode>		AndNodes;
	vector<COrNode>			OrNodes;
	int						Root;
	int						Width, Height;

public:
	bool InputFromStream(istream& inStream);
	void OutputToStream(ostream& outStream) const;
};

typedef struct DenseNode
{
	double		pos_ori, pos_len;
	double		dir;
} DenseNodeType;

typedef struct tagEdgeCurve
{
	vector<DenseNodeType>	Curve;
	double					NodeDir, NodeLen;
	int						LeafID1, LeafID2;
} EdgeCurveType;

typedef	struct  tagArcModel
{
	int			ArcType;
	int			RootID, LeafID1, LeafID2;
	double		ScaleWeight, RotWeight;
} ArcModelType;

typedef	struct  tagModelTree
{
	vector<CAndNodeModel>		AndModels;
	vector<COrNodeModel>		OrModels;
	vector<CLeafNodeModel>		LeafModels;
	TMatrix<double>				LeafLenInfo;
	TMatrix<double>				LeafDirInfo;
	vector<EdgeCurveType>		Curves;
	vector<ArcModelType>		Rules;
	int							Root;
	int							MaxLevel;
	// In Inference
	int							RuleStep;

	vector<bool> List_fIfNodeWork;

//public:
//	ModelTreeType()
//	{
//		AndModels.clear(); OrModels.clear(); LeafModels.clear();
//		Curves.clear(); Rules.clear();
//		Root = -1; MaxLevel = -1; RuleStep = -1;
//		List_fIfNodeWork.clear();
//	}
} ModelTreeType;

// Threshold
typedef struct tagInstThres
{
	int			ImageID;
	double		AvgLeafDist;
	double		Score;
} InstThresType;
